<!DOCTYPE HTML>
<!--
	Dimension by HTML5 UP
	html5up.net | @ajlkn
	Free for personal and commercial use under the CCA 3.0 license (html5up.net/license)
-->
<html>
 <head>
  <title>
   Dimension by HTML5 UP
  </title>
  <!-- <meta charset="utf-8" /> -->
  <!-- <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" /> -->
  <meta charset="utf-8"/>
  <meta content="width=device-width,initial-scale=1.0" name="viewport"/>
  <link href="../../assets/css/article.css" rel="stylesheet"/>
  <link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet"/>
  <noscript>
   <link href="../../assets/css/noscript.css" rel="stylesheet"/>
  </noscript>
 </head>
 <body>
  <div id="app">
  </div>
  <!-- built files will be auto injected -->
 </body>
 <body class="is-preload">
  <!-- Wrapper -->
  <div id="wrapper">
   <!-- Main -->
   <div id="main">
    <article id="article">
     <h1 id="java">
      Java类加载器
     </h1>
     <hr/>
     <h2 id="_1">
      简介
     </h2>
     <p>
      介绍类加载器的分类和特性
     </p>
     <h2 id="_2">
      类加载器
     </h2>
     <p>
      <img alt="" src="https://p6-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e3d2936144d04af09f6e59a25a545ef7~tplv-k3u1fbpfcp-watermark.image"/>
     </p>
     <h3 id="_3">
      加载器类型
     </h3>
     <p>
      如上图所示，类加载器大致可分为四大类，如上他们是有父子关系的，启动类加载器最先开始（用C++写的），后面加载上子加载器
     </p>
     <ul>
      <li>
       1.启动类加载器
      </li>
      <li>
       2.扩展类加载器
      </li>
      <li>
       3.应用类加载器
      </li>
      <li>
       4.自定义类加载器
      </li>
     </ul>
     <p>
      在Java9之前，大致类加载器功能如下：
     </p>
     <p>
      启动类加载器：负责加载最为基础的类、最为重要的类，比如存放在JRE的lib目录下的jar包中的类（以及由虚拟机参数 -Xbootclasspath 指定的类）
     </p>
     <p>
      扩展类加载器：负责加载相对次要、但又通用的类，比如存放在JRE的lib/ext目录的jar包重点类（以及由系统变量java.ext.dirs指定的类）
     </p>
     <p>
      应用类加载器：负责加载应用程序路径下的类（应用程序路径指虚拟机参数 -cp/-classpath、系统变量 java.class.path 或环境变量 CLASSPATH所指定的路径）
     </p>
     <p>
      自定义类加载器：负责加载自定义的特殊的类。比如对class文件进行加密后，利用自定义的类加载器进行解密加载。
     </p>
     <p>
      自定义加载器还有一个骚操作，功能描述大致如下：
     </p>
     <blockquote>
      <p>
       在 Java 虚拟机中，类的唯一性是由类加载器实例以及类的全名一同确定的。即便是同一串字节流，经由不同的类加载器加载，也会得到两个不同的类。在大型应用中，我们往往借助这一特性，来运行同一个类的不同版本。
      </p>
     </blockquote>
     <h3 id="_4">
      双亲委托机制
     </h3>
     <p>
      类加载器有个非常重要的机制：双亲委托机制
     </p>
     <blockquote>
      <p>
       当类加载器要加载一个类时，如果自己曾经没有加载过这个类，则层层向上委托给父加载器尝试加载。如果父加载器都没有，才自己进行加载
      </p>
     </blockquote>
     <p>
      为什么需要双亲委托机制呢：因为用它可以保证类的唯一性
     </p>
     <h3 id="_5">
      添加引用类的几种方式
     </h3>
     <p>
      通过的前面的介绍，我们可以得到下面几种引用类的添加方式
     </p>
     <ul>
      <li>
       1.放到JDK的 lib/ext 下，或者 -Djava.ext.dirs
      </li>
      <li>
       2.java -cp/classpath 或者 class 文件放到当前目录
      </li>
      <li>
       3.自定义 ClassLoader 加载
      </li>
      <li>
       4.拿到当前执行类的 ClassLoader，反射调用 addURL 方法添加 Jar 或者 路径(JDK9无效)
      </li>
     </ul>
     <h3 id="_6">
      自定义加载器的一些玩法
     </h3>
     <h4 id="_7">
      加载两个同名类
     </h4>
     <p>
      虽然双亲委托机制保证了类的唯一性，但是只是父子关系才行，如果是兄弟关系，那就可以加载同一个类
     </p>
     <p>
      在前面说过，类的唯一性是由类加载器+类名进行确定的,如同下面的代码，虽然都是同一个类，但通过不同的类加载器进行加载，被视为不同的类
     </p>
     <div class="codehilite">
      <pre><span></span><code><span class="kn">import</span> <span class="nn">java.lang.reflect.Method</span><span class="p">;</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">Test</span> <span class="p">{</span>
    <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="p">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="p">)</span> <span class="p">{</span>
        <span class="n">CustomClassLoader</span> <span class="n">classLoader1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CustomClassLoader</span><span class="p">(</span><span class="s">"/Users/yu/Desktop/lib"</span><span class="p">);</span>
        <span class="n">CustomClassLoader</span> <span class="n">classLoader2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">CustomClassLoader</span><span class="p">(</span><span class="s">"/Users/yu/Desktop/lib"</span><span class="p">);</span>
        <span class="k">try</span> <span class="p">{</span>
            <span class="n">Class</span> <span class="n">c1</span> <span class="o">=</span> <span class="n">classLoader1</span><span class="p">.</span><span class="na">findClass</span><span class="p">(</span><span class="s">"Person"</span><span class="p">);</span>
            <span class="n">Object</span> <span class="n">instance1</span> <span class="o">=</span> <span class="n">c1</span><span class="p">.</span><span class="na">newInstance</span><span class="p">();</span>

            <span class="n">Class</span> <span class="n">c2</span> <span class="o">=</span> <span class="n">classLoader2</span><span class="p">.</span><span class="na">findClass</span><span class="p">(</span><span class="s">"Person"</span><span class="p">);</span>
            <span class="n">Object</span> <span class="n">instance2</span> <span class="o">=</span> <span class="n">c2</span><span class="p">.</span><span class="na">newInstance</span><span class="p">();</span>

            <span class="n">Method</span> <span class="n">method</span> <span class="o">=</span> <span class="n">c1</span><span class="p">.</span><span class="na">getDeclaredMethod</span><span class="p">(</span><span class="s">"setPerson"</span><span class="p">,</span> <span class="n">Object</span><span class="p">.</span><span class="na">class</span><span class="p">);</span>
            <span class="n">method</span><span class="p">.</span><span class="na">invoke</span><span class="p">(</span><span class="n">instance1</span><span class="p">,</span> <span class="n">instance2</span><span class="p">);</span>
        <span class="p">}</span> <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">e</span><span class="p">)</span> <span class="p">{</span>
            <span class="n">e</span><span class="p">.</span><span class="na">printStackTrace</span><span class="p">();</span>
        <span class="p">}</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre>
     </div>
     <h2 id="_8">
      参考资料
     </h2>
     <ul>
      <li>
       <a href="https://juejin.cn/post/6844903780031397902#heading-10">
        探秘类加载器和类加载机制
       </a>
      </li>
      <li>
       <a href="https://time.geekbang.org/column/article/11523">
        03 | Java虚拟机是如何加载Java类的?
       </a>
      </li>
      <li>
       <a href="https://time.geekbang.org/column/article/10076">
        第24讲 | 有哪些方法可以在运行时动态生成一个Java类？
       </a>
      </li>
     </ul>
    </article>
   </div>
   <!-- Footer -->
   <footer id="footer">
    <p class="copyright">
     © Untitled. Design:
     <a href="https://html5up.net">
      HTML5 UP
     </a>
     .
    </p>
   </footer>
  </div>
  <!-- BG -->
  <div id="bg">
  </div>
  <!-- Scripts -->
  <script src="../assets/js/jquery.min.js">
  </script>
  <script src="../assets/js/browser.min.js">
  </script>
  <script src="../assets/js/breakpoints.min.js">
  </script>
  <script src="../assets/js/util.js">
  </script>
  <script src="../assets/js/main.js">
  </script>
 </body>
</html>
